package fi.iki.joker.mobilogger.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

import fi.iki.joker.mobilogger.exception.PicasaWebException;
import fi.iki.joker.mobilogger.img.ImageRepositoryConstants;

import android.util.Log;
import android.util.Xml;


public class PicasaWebUtil {
	
	private final String TAG = "PicasaWebUtil";
	private final String ALBUMS_FEED = "http://picasaweb.google.com/data/feed/api/user/default?kind=album&access=all";
	private final String IMAGE_POST_URL = "http://picasaweb.google.com/data/feed/api/user/userID/albumid/albumID";
	private HttpClient httpClient;
	/**
	 * This transport object is used as a container for one particular Picasa web
	 * album.
	 * @author jkervine
	 *
	 */
	
	public class PicasaWebAlbumTO {
		
		private String id;
		private String name;
		
		public String getId() {
			return id;
		}
		public void setId(String id) {
			this.id = id;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		
	}
	
	/**
	 * This class encapsulates the methods used for the SAX parser
	 * of the albums response
	 */
	
	private class PicasaAlbumsResponseParser implements ContentHandler {

		private boolean inEntry = false;
		private boolean inId = false;
		private boolean inTitle = false;
		private LinkedList<PicasaWebAlbumTO> results;
		private int indexOfFoundEntry = -1;
		private PicasaWebAlbumTO currentEntry = null;
		
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			String chars = (new String(ch).substring(start, start + length));
			//the last clause of the condition is to distinguish between the tags "id" and gphoto:id, which both
			// trigger the inId condition. Arguably a hack - but we don't now need to worry about setting
			//any sax parser properties to make the namespaces work right.
			if(inEntry && inId && chars.contains("albumid")) {
				currentEntry.setId(chars);
			}
			if(inEntry && inTitle) {
				currentEntry.setName(chars);
			}
		}

		public void endDocument() throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			// TODO Auto-generated method stub
			if(localName.trim().equals("id")) {
				inId = false;
			} else if (localName.trim().equals("entry")) {
				inEntry = false;
				results.add(currentEntry);
			} else if (localName.trim().equals("title")) {
				inTitle = false;
			}
		}

		public void endPrefixMapping(String prefix) throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void startElement(String uri, String localName, String qName,
				Attributes atts) throws SAXException {
			// TODO Auto-generated method stub
			if(localName.trim().equals("entry")) {
				inEntry = true;
				indexOfFoundEntry++;
				currentEntry = new PicasaWebAlbumTO();
			}
			if(localName.trim().equals("id")) {
				inId = true;
			}
			if(localName.trim().equals("title")) {
				inTitle = true;
			}
		}

		public void ignorableWhitespace(char[] ch, int start, int length)
				throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void processingInstruction(String target, String data)
				throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void setDocumentLocator(Locator locator) {
			// TODO Auto-generated method stub
			
		}

		public void skippedEntity(String name) throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void startDocument() throws SAXException {
			results = new LinkedList<PicasaWebAlbumTO>();			
		}

		public void startPrefixMapping(String prefix, String uri)
				throws SAXException {
			// TODO Auto-generated method stub
			
		}
		
		public LinkedList<PicasaWebAlbumTO> getResult() {
			return results;
		}
	};
	
	/**
	 * This class encapsulates the methods used for the SAX parser
	 * of the image publish response
	 */
	
	private class PicasaPublishResponseParser implements ContentHandler {

		private boolean inEntry = false;
		private String publishedContentSource = null;
		
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			return;
		}

		public void endDocument() throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			// TODO Auto-generated method stub
			if (localName.trim().equals("entry")) {
				inEntry = false;
			} 
		}

		public void endPrefixMapping(String prefix) throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void startElement(String uri, String localName, String qName,
				Attributes attrs) throws SAXException {
			// TODO Auto-generated method stub
			if(localName.trim().equals("entry")) {
				inEntry = true;
			}	
			if(localName.trim().equals("content")) {
				if(inEntry) {
					Log.d(TAG,"Found Entry->Content, attributes count:"+attrs.getLength());
					for(int i = 0; i < attrs.getLength();i++) {
						Log.d(TAG,"Attribute "+i+": "+attrs.getLocalName(i)+" = "+attrs.getValue(i));
					}
					// This has a "feature" it: it actually finds the tag media:content!!!
					// This is actually a better place than the entry -> content -> @src (has image dimensions and thumbnails)
					publishedContentSource = attrs.getValue("url");
					if(publishedContentSource == null || publishedContentSource.equals("")) {
						Log.e(TAG,"Looks like there's something wrong with the image content source."+ 
								"Got null or empty source even if we should be in right place of the source.");
					}
				}
			}
		}

		public void ignorableWhitespace(char[] ch, int start, int length)
				throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void processingInstruction(String target, String data)
				throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void setDocumentLocator(Locator locator) {
			// TODO Auto-generated method stub
			
		}

		public void skippedEntity(String name) throws SAXException {
			// TODO Auto-generated method stub
			
		}

		public void startDocument() throws SAXException {
			publishedContentSource = null;			
		}

		public void startPrefixMapping(String prefix, String uri)
				throws SAXException {
			// TODO Auto-generated method stub
			
		}
		
		public String getPublishedContentSource() {
			return publishedContentSource;
		}
	};
	
	/**
	 * 
	 */
	
	public String uploadPhotoToAlbum(String authToken, String feedURL, String fileName, long fLength, InputStream fileContents) 
		throws PicasaWebException {
		HttpPost postUpload = new HttpPost(feedURL);
		Log.d(TAG,"This photo ("+fileName+") is going out to album URL: "+feedURL);
		HttpResponse response = null;
		InputStreamEntity imageBytes = null;
		imageBytes = new InputStreamEntity(fileContents,fLength);
		int rescode = -1;
		String res = null;
		Header authHeader = new BasicHeader("Authorization", "GoogleLogin auth="+authToken);
		Header typeheader = new BasicHeader("Content-Type", "image/jpeg");
		Header slugHeader = new BasicHeader("Slug",fileName);
		try {
			postUpload.setEntity(new StringEntity("Slug: "+fileName+"\n"));
			postUpload.setEntity(new StringEntity("Content-Length: "+fLength+"\n"));
			postUpload.setEntity(new StringEntity("Content-Type: image/jpeg\n"));
		} catch (UnsupportedEncodingException e) {
			Log.e(TAG,"Unsupported encoding: "+e.getMessage());
		}
		postUpload.setHeader(authHeader);
		postUpload.setHeader(typeheader);
		postUpload.setHeader(slugHeader);
		postUpload.setEntity(imageBytes);
		if(httpClient == null) {
			httpClient = new DefaultHttpClient();
		}
		try {
			response = httpClient.execute(postUpload);
			if(response != null) {
				rescode = response.getStatusLine().getStatusCode();
				res = StreamUtil.convertStreamToString(response.getEntity().getContent());
			}
			Log.d(TAG,"Response code: "+rescode);
			Log.d(TAG,"Response body: "+res);
		} catch (IOException ie) {
			Log.e(TAG,"IOException during client comms:"+ie.getMessage());
			throw new PicasaWebException(ie);
		} finally {
			Log.d(TAG,"Executed POST request to PicasaWeb without exceptions.");
		}
		//Get the published image's URL from the response and return that to caller
		PicasaPublishResponseParser parserImpl = new PicasaPublishResponseParser();
		try {
			Xml.parse(res, parserImpl);
		} catch (SAXException e) {
			Log.e(TAG, "Parsing of the picasa image publish response failed.");
			e.printStackTrace();
			throw new PicasaWebException("SAXException while parsing picasa publish response: "+e.getMessage());
		}
		return parserImpl.getPublishedContentSource();
	}
	
	/**
	 * Executes a HTTP GET to the albums fetch URL and returns a set of albums
	 * that the authenticated user has.
	 * TODO:add proper error handling!
	 */
	
	public LinkedList<PicasaWebAlbumTO> getAlbums(String authToken) throws PicasaWebException {
		HttpGet fetchGet = new HttpGet(ALBUMS_FEED);
		HttpResponse response = null;
		Header authHeader = new BasicHeader("Authorization", "GoogleLogin auth="+authToken);
		int rescode = -1;
		String res = null;
		fetchGet.setHeader(authHeader);
		if(httpClient == null) {
			httpClient = new DefaultHttpClient();
		}
		try {
			response = httpClient.execute(fetchGet);
			if(response != null) {
				rescode = response.getStatusLine().getStatusCode();
				res = StreamUtil.convertStreamToString(response.getEntity().getContent());
			}
			Log.d(TAG,"Response code: "+rescode);
			Log.d(TAG,"Response body: "+res);
			
		} catch (IOException ie) {
			Log.e(TAG,"IOException during client comms:"+ie.getMessage());
			throw new PicasaWebException(ie);
		} finally {
			Log.d(TAG,"Executed GET request to Google without exceptions.");
		}
		PicasaAlbumsResponseParser parserImpl = new PicasaAlbumsResponseParser();
		try {
			Xml.parse(res, parserImpl);
		} catch (SAXException e) {
			Log.e(TAG, "Parsing of the picasa albums feed response failed.");
			e.printStackTrace();
			throw new PicasaWebException("SAXException while parsing getAlbums response: "+e.getMessage());
		}
		return parserImpl.getResult();
	}
	
}
